#include"comm.hpp"
extern Log log;
//读取方设计思路：
//双方通过管道和共享内存进行通信，管道用来辅助控制共享内存的使用
//只有写入方写入数据到管道后，再发送一个字符给管道，读取发方一直阻塞在读取管道数据，读取到管道数据后，就说明写入方已经往共享内存段写入数据了，此时可以直接获取共享内存中的数据
//注意：共享内存的可以直接使用，并不需要管道，我们设置管道只是为了监控写入方是否写入数据而已
int main()
{
        Init it;//创建管道
        log.Enable(Mulfile);//设置日志为多文件打印

        int shmid=CreateShm();

        //挂接共享内存段到进程的共享地址段，从而进程可以直接使用这段共享内存空间，进行写入或者读取
        //本质就是把共享内存的空间映射到进程的虚拟空间的共享内存段，并且返回共享段的指针地址，从而实现共享内存的挂接
        char*shmaddr=(char*)shmat(shmid,nullptr,0);//shmat 函数用于将共享内存段与调用进程的地址空间关联起来，使得该进程可以访问这段共享内存。
        //也就是引用这块空间，此时这块共享内存的引用计数+1,返回值是进程中内存共享段的地址

        //一旦有人把数据写入共享内存，我们立刻就能看到，不需要系统调用
        int fd=open(FIFO_FILE,O_RDONLY);//阻塞等待写入方打开管道
        if(fd<0)
        {
            log(Fatal,"error string :%s ,error code: %d",strerror(errno),errno);
            exit(FIFO_OPEN_ERR);
        }

        //shmid_ds 是在 <sys/shm.h> 中定义的结构体，用于描述共享内存段的状态和属性。它包含了关于共享内存的多种信息。
        struct shmid_ds shmds;
        while(true)
        {
            char c;
            ssize_t s=read(fd,&c,1);//阻塞的方式从管道中读取数据
            if(s==0)break;//写入端关闭的时候就会非阻塞一直读到0，就会退出
            else if(s<0)break;
            cout<<"client say@"<<shmaddr<<endl;//直接把共享内存段的内容当做一个字符串的方式输出，挂接后的共享内存可以直接通过指向其地址的字符指针使用
            sleep(1);
            //直接访问共享内存：
            shmctl(shmid,IPC_STAT,&shmds);//把开辟的共享内存的属性输出给结构体shmds
            //输出共享内存的属性：
            cout<<"shm size"<<shmds.shm_segsz<<endl;
            cout<<"shm nattch:"<<shmds.shm_nattch<<endl;
            printf("shm key:0x%x\n",shmds.shm_perm.__key);
            cout<<"shm mode:"<<shmds.shm_perm.mode<<endl;
        }
        //断开共享段
        shmdt(shmaddr);//shmaddr 是指向要断开的共享内存段的指针。通常，在调用 shmget 创建共享内存段后，使用 shmat 将其附加到进程的地址空间，之后可以使用 shmdt 断开。
        //删除共享段
        shmctl(shmid,IPC_RMID,nullptr);//IPC_RMID是请求删除
        close(fd);
        return 0;

 }

 //运行过程中使用ipcs -m可监控共享内存的使用，在程序运行过程中，我们会看到我们的创建的共享内存被读取方创建并挂接，此时的共享内存的引用计数为1，在写入方打开并挂接共享内存后，引用计数变为2，在关闭写入方之后，读取方管道读取到0退出读取循环，然后读取方放会取消挂接并且删除共享内存

//测试：
// int main()
// {
//     int shmid=GetShm();

//     sleep(2);

//     char*shmaddr=(char*)shmat(shmid,nullptr,0);

//     sleep(2);

//     shmdt(shmaddr);

//     sleep(1);

//     return 0;
// }
